package com.example.puback.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * @version 1.0.0
 * @className: MyCallBack
 * @description: 消息生产者发布消息后的回调接口
 * @author: LiJunYi
 * @create: 2022/8/4 15:05
 */
@Component
@Slf4j
public class MyCallBack implements RabbitTemplate.ConfirmCallback,RabbitTemplate.ReturnsCallback
{
    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 该注解会在其他注解执行完毕之后，进行一个属性的注入，必须将该类注入到rabbitTemplate的内部类中,内部类就是这个ConfirmCallback
     */
    @PostConstruct
    public void init(){
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnsCallback(this);
    }

    /**
     * 交换机不管是否收到消息的一个回调方法
     * 1. 发消息 交换机接收到了 回调
     * @param correlationData 包含了消息的ID和其他数据信息 这个需要在发送方创建，否则没有
     * @param ack             返回的一个交换机确认状态 true 为确认 false 为未确认
     * @param cause           未确认的一个原因，如果ack为true的话，此值为null
     */
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause)
    {
        String id = correlationData != null ? correlationData.getId() : "";
        if (ack){
            log.info("消息发送成功，id 是{} ",id);
        }else{
            log.info("消息发送失败，原因 是{} id 为{}",cause,id);
        }
    }

    /**
     * 可以在消息传递过程中，如果交换机遇到不可路由的情况，会将消息返回给生产者
     * returned#message 消息
     * returned#replyCode 回复状态码
     * returned#replyText 退回原因
     * returned#exchange 交换机
     * returned#routingKey 路由Key
     * @param returned 返回
     */
    @Override
    public void returnedMessage(ReturnedMessage returned)
    {
        log.error("消息{},被交换机{}退回，退回原因:{},路由key:{}",
                new String(returned.getMessage().getBody()),returned.getExchange(),
                returned.getReplyText(),returned.getRoutingKey());
    }
}
